#include"common.h"
#define USE_PCM_SAVE 0
static AVFormatContext*fmt_ctx;
static AVCodecContext *dec_ctx;
static int audio_stream_index = -1;
static int running = 1;
#if USE_PCM_SAVE
static FILE*pcmfp=NULL;
#endif
int  open_input_file_audio(const char *filename);
void print_frame(const AVFrame *frame);
int read_next_audio_frame(AVFrame *frame);
#if USE_SDL_LIB
static char*pcmbuffer = NULL;
void my_audio_callback(void *userdata, Uint8 *stream, int len);
#endif
int TestFilterAudio(const char*filename){
	int ret;
#if USE_SDL_LIB
	SDL_AudioSpec desired = { 0 };
#endif
	AVFrame *frame = av_frame_alloc();
	avcodec_register_all();
	av_register_all();
	if ((ret = open_input_file_audio(filename)) < 0)
		goto end;
#if USE_PCM_SAVE
	pcmfp =fopen("test.pcm","wb");
#endif
#if USE_SDL_LIB
	SDL_Init(SDL_INIT_AUDIO);
	do {
		SDL_AudioSpec desired = { 0 };
		desired.format = AUDIO_S16;
		desired.channels = dec_ctx->channels;
		desired.freq = dec_ctx->sample_rate;
		desired.samples = dec_ctx->frame_size;
		desired.callback = my_audio_callback;
		desired.userdata = frame;
		pcmbuffer = (char*)malloc(dec_ctx->frame_size* dec_ctx->channels * sizeof(uint16_t));
		SDL_OpenAudio(&desired, NULL);
		SDL_PauseAudio(0);
	} while (0);
	while (running) {
		SDL_Event event = { 0 };
		SDL_PollEvent(&event);
		if (event.type == SDL_QUIT) {
			printf("Recv Quit Single\n");
			running = 0;
		}
	}
#else
	/* read all packets */
	while (1) {
		if (read_next_audio_frame(frame) < 0) {
			break;
		}
	}
#endif	
end:
	if (dec_ctx)
		avcodec_close(dec_ctx);
	avformat_close_input(&fmt_ctx);
	av_frame_free(&frame);
#if USE_PCM_SAVE
	if(pcmfp !=NULL)fclose(pcmfp);
#endif
#if USE_SDL_LIB
	SDL_CloseAudio();
	if (pcmbuffer)free(pcmbuffer);
	SDL_Quit();
#endif
	if (ret < 0 && ret != AVERROR_EOF) {
		char buf[1024];
		av_strerror(ret, buf, sizeof(buf));
		fprintf(stderr, "Error occurred: %s\n", buf);
		exit(1);
	}
	return 0;
}

int open_input_file_audio(const char *filename)
{
	int ret;
	AVCodec *dec;

	if ((ret = avformat_open_input(&fmt_ctx, filename, NULL, NULL)) < 0) {
		av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");
		return ret;
	}

	if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
		av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");
		return ret;
	}

	/* select the audio stream */
	ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, &dec, 0);
	if (ret < 0) {
		av_log(NULL, AV_LOG_ERROR, "Cannot find a audio stream in the input file\n");
		return ret;
	}
	audio_stream_index = ret;
	dec_ctx = fmt_ctx->streams[audio_stream_index]->codec;
	//av_opt_set_int(dec_ctx, "refcounted_frames", 1, 0);

	/* init the audio decoder */
	if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) {
		av_log(NULL, AV_LOG_ERROR, "Cannot open audio decoder\n");
		return ret;
	}

	printf("codec:%s(%s) sample_rate:%d samples:%d channels:%d\n", 
	avcodec_get_name(dec_ctx->codec_id), av_get_sample_fmt_name(dec_ctx->sample_fmt),
	dec_ctx->sample_rate, dec_ctx->frame_size, dec_ctx->channels);
	return 0;
}

void print_frame(const AVFrame *frame){
	const float *pl     = (float*)frame->data[0];
	const float *pr     = (float*)frame->data[1];
	int i;
#if USE_SDL_LIB
	char *pos = pcmbuffer;
#endif
	for (i=0;i<frame->nb_samples;i++){
		uint16_t tmpl = *pl * 32767;
		uint16_t tmpr = *pr * 32767;
		pl++;
		pr++;
#if USE_PCM_SAVE
		if (pcmfp !=NULL){			
			fwrite(&tmpl,1,sizeof(uint16_t), pcmfp);
			fwrite(&tmpr,1,sizeof(uint16_t), pcmfp);
		}
#endif
#if USE_SDL_LIB
		memcpy(pos, &tmpl, sizeof(uint16_t));
		pos += sizeof(uint16_t);
		memcpy(pos, &tmpr, sizeof(uint16_t));
		pos += sizeof(uint16_t);
#endif
	}
}
int read_next_audio_frame(AVFrame *frame) {
	int ret;
	while (1) {
		int got_frame;
		AVPacket packet;
		if ((ret = av_read_frame(fmt_ctx, &packet)) < 0)
			break;
		if (packet.stream_index == audio_stream_index) {
			//avcodec_get_frame_defaults(frame);
			got_frame = 0;
			ret = avcodec_decode_audio4(dec_ctx, frame, &got_frame, &packet);
			if (ret < 0) {
				av_log(NULL, AV_LOG_ERROR, "Error decoding audio\n");
				continue;
			}

			if (got_frame) {
				print_frame(frame);
				break;
			}
		}
		av_free_packet(&packet);
	}
	return ret;
}
#if USE_SDL_LIB
void my_audio_callback(void *userdata,Uint8 *stream, int len) {
	AVFrame *frame = (AVFrame *)userdata;
	SDL_memset(stream, 0, len);
	if (read_next_audio_frame(frame) < 0) {
		running = 0;
	}	else {
		SDL_MixAudio(stream, pcmbuffer, frame->nb_samples*2* sizeof(uint16_t), SDL_MIX_MAXVOLUME);
		SDL_memcpy(stream, pcmbuffer, 4096);
   	}
}
#endif